// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BacklightNativeMethods.cs" company="Roman '4ux-nbIx' Novitsky">
//   Copyright (c) Roman '4ux-nbIx' Novitsky 2010
// </copyright>
// <summary>
//   Defines the BacklightNativeMethods type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace MtgMC.WindowsNative
{
    #region Namespace Imports

    using System;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.InteropServices;
    using System.Threading;

    using Microsoft.Win32;

    #endregion


    /// <summary>
    /// Contains back light helper methods.
    /// </summary>
    public static class BacklightNativeMethods
    {
        #region Constants and Fields

        private static Thread _thread;
        private static IntPtr _userActivityEvent;

        #endregion


        #region Public Methods

        /// <summary>
        /// Starts keeping the backlight on.
        /// </summary>
        public static void StartKeepingBacklightOn()
        {
            if (_thread != null)
            {
                return;
            }

            _thread = new Thread(KeepBacklightOn);
            _thread.Start();
        }


        /// <summary>
        /// Stops keeping the backlight on.
        /// </summary>
        public static void StopKeepingBacklightOn()
        {
            if (_thread == null)
            {
                return;
            }

            _thread.Abort();
            _thread = null;

            ResetEvent(_userActivityEvent);
            CloseHandle(_userActivityEvent);
        }

        #endregion


        #region Methods

        [DllImport("coredll.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi, 
            CharSet = CharSet.Auto)]
        private static extern IntPtr CreateEvent(
            IntPtr eventAttributes, 
            [In] [MarshalAs(UnmanagedType.Bool)] bool isManualReset, 
            [In] [MarshalAs(UnmanagedType.Bool)] bool intialState, 
            [In] [MarshalAs(UnmanagedType.BStr)] string name);


        [DllImport("coredll.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool EventModify(IntPtr eventHandle, [In] [MarshalAs(UnmanagedType.U4)] int eventId);


        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", 
            MessageId = "MtgMC.WindowsNative.BacklightNativeMethods.WaitForSingleObject(System.IntPtr,System.Int32)", 
            Justification = "Don't care.")]
        private static void KeepBacklightOn()
        {
            if (_userActivityEvent == IntPtr.Zero)
            {
                CreateEventHandle();

                if (_userActivityEvent == IntPtr.Zero)
                {
                    return;
                }
            }

            var timeOut = new TimeSpan(0, 0, 10);

            while (true)
            {
                WaitForSingleObject(_userActivityEvent, (int)timeOut.TotalMilliseconds);

                ResetIdleTimer();
            }
        }


        [DllImport("coredll.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi, 
            CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);


        private static bool ResetEvent(IntPtr eventHandle)
        {
            return EventModify(eventHandle, (int)EventFlag.EventReset);
        }


        private static void ResetIdleTimer()
        {
            if (Environment.OSVersion.Version.Major <= 5)
            {
                // Windows CE 5.0, Windows Mobile, or older CE APIs called
                SystemIdleTimerReset();
            }
            else
            {
                // Windows CE 6.0 uses event
                CreateEventHandle();

                if (_userActivityEvent != IntPtr.Zero)
                {
                    // Signal user activity to the GWE and Backlight driver
                    SetEvent(_userActivityEvent);
                }
            }
        }


        private static bool SetEvent(IntPtr eventHandle)
        {
            return EventModify(eventHandle, (int)EventFlag.EventSet);
        }


        [DllImport("coredll", SetLastError = true)]
        private static extern void SystemIdleTimerReset();


        [DllImport("coredll.dll", SetLastError = true)]
        private static extern int WaitForSingleObject(IntPtr handle, int timeout);


        private static void CreateEventHandle()
        {
            if (_userActivityEvent != IntPtr.Zero)
            {
                return;
            }

            using (RegistryKey key = Registry.LocalMachine.OpenSubKey("System\\GWE"))
            {
                object value = key.GetValue("ActivityEvent");
                key.Close();

                if (value == null)
                {
                    return;
                }

                var activityEventName = (string)value;
                _userActivityEvent = CreateEvent(IntPtr.Zero, false, true, activityEventName);
            }
        }

        #endregion
    }
}